import java.util.ArrayList;
import java.util.List;

/**
 * Holds the names of all directives in the language, whether or not they affect memory,
 * and whether a label is required, option, or not allowed.<br><Br>
 * Change Log:<br><br>
 * 	- 04/06/09 - Tobin Chee<br>
 * 		- Created initial skeleton.<br><br>
 * 	- 04/09/09 - Ben Tarney<br>
 * 		- Populated directivesKey with directives Strings.<br>
 * 		- Populated directivesMemImpact with boolean values.<br><br>
 *  - 04/13/09 - Ben Tarney<br>
 *  	- Changed EQU to false on directivesMemimpact. Listed incorrectly in course handouts. Al corrected in class.<br><br>
 *  - 04/13/09 - Meghan Day<br>
 *  	- Added machineOpsOperandTypes list.<br><br>
 *  - 04/15/09 - Meghan Day<br>
 *  	- Changed machineOpsOperandTypes to integer rep.<br><br>
 *  - 04/16/09 - Ben Tarney<br>
 *  	- Added the directiveLabelAllowed list and populated with values.<br><br>
 *  - 04/17/09 - Meghan Day<br>
 *  	- Updated documentation of operand types.<br><br>
 *  - 04/18/09 - Meghan Day<br>
 *  	- Populated directivesOperandType and updated other list to match changes in specs.<br><br>
 *  - 04/19/09 - Meghan Day<br>
 *  	- Changed LabelAllowed list to enumeration.<br><br>
 * 	- 04/27/09 - Meghan Day<br>
 * 		- Added new operand type PRMLST.<br><br>
 *  - 05/03/09 - Meghan Day<br>
 *  	- Added items from change logs of operations to change log of the whole class, because
 *  	that's how it's supposed to be.<br><br>
 *  - 05/05/09 - Tobin Chee<br>
 *  	- Changed directive "FINISH" to "FINSH" to match proper CSE7000 specifications.
 */
public class DirectivesTable {
	/** 
	 * Represents the directive name column of the table.
	 */
	private List<String> directivesKey = new ArrayList<String>();
	/**
	 * Represents whether the directives consume memory.
	 */
	private List<Boolean> directivesMemImpact = new ArrayList<Boolean>();
	/**
	 * Represents whether a label is required, optional, or not allowed for each directive.
	 */
	private List<Assembler.LabelAllowed> directivesLabelAllowed = new ArrayList<Assembler.LabelAllowed>();
	/**
	 * Represents which group of directives having similar operand the
	 * specific directive belongs to.<br>
	 * 0 - No operands<br>
	 * 1 - Mem_ref<br>
	 * 2 - Number or equated symbol<br>
	 * 3 - IOWD<br>
	 * 4 - EXR<br>
	 * 5 - CALL<br>
	 * 6 - EQU<br>
	 * 7 - EXTRN<br>
	 * 8 - String only<br>
	 * 9 - PRMID<br>
	 * 10 - ADRC<br>
	 * 11 - BSS<br>
	 * 12 - DEC<br>
	 * 13 - HEX<br>
	 * 14 - OCT<br>
	 * 15 - DEBUG<br>
	 * 16 - ALT<br>
	 * 17 - PRMLST<br>
	 * 18 - AVERT
	 */
	private List<Integer> directivesOperandType = new ArrayList<Integer>();
	
	/** Construct and populate a directives table.
	 */
	public DirectivesTable(){
		this.populateTable();
	}
	
	/**
	 * Returns the number representing the format of the directive's operands.
	 * @param key The name of the directive.
	 * @return The number representing the format of the operands.
	 */
	public int getOperandType(String key){
		key = key.toUpperCase();
		int index = directivesKey.indexOf(key);
		return directivesOperandType.get(index);
	}
	
	/**
	 * Returns whether a directive is in the table or not.
	 * @param key The name of the directive to look for.
	 * @return True if the directive exists in the table.
	 */
	public boolean containsDirective(String key){
		key = key.toUpperCase();
		return directivesKey.contains(key);
	}
	
	/**
	 * Returns whether a directive in the table consumes memory.
	 * @param key The name of the directive to look for.  Must be in the table.
	 * @return True if the directive consumes memory.
	 */
	public boolean consumesMemory(String key){
		key = key.toUpperCase();
		int index = directivesKey.indexOf(key);
		return directivesMemImpact.get(index);
	}
	
	/**
	 * Returns whether the directive is required, allowed, or not allowed to have a label.
	 * @param key The name of the directive to look for.  key must be in the table.
	 * @return The corresponding values of enumeration LabelAllowed in Assembler.java to<br>
	 * required, optional, and not allowed.
	 */
	public Assembler.LabelAllowed isLabelAllowed(String key){
		int index = directivesKey.indexOf(key);
		return directivesLabelAllowed.get(index);
	}
	
	/**
	 * Populates the table with all the machine's directives and their associated values in
	 * directiveMemImpact, directivesLabelAllowed, and directivesOperandTypes.<br><br>
	 * Change Log:<br>
	 * 	- 04/06/09 - Tobin Chee<br>
	 * 		- Created initial skeleton.<br><br>
	 * 	- 04/09/09 - Ben Tarney<br>
	 * 		- Populated directivesKey with directives Strings.<br>
	 * 		- Populated directivesMemImpact with boolean values.<br><br>
	 *  - 04/13/09 - Ben Tarney<br>
	 *  	- Changed EQU to false on directivesMemimpact. Listed incorrectly in course handouts. Al corrected in class.<br><br>
	 *  - 04/16/09 - Ben Tarney<br>
	 *  	- Added the directiveLabelAllowed list and populated with values<br><br>
	 *  - 04/18/09 - Meghan Day<br>
	 *  	- Populated directivesOperandType and updated other list to match changes in specs<br><br>
	 *  - 04/19/09 - Meghan Day<br>
	 *  	- Changed LabelAllowed list to enumeration
	 */
	private void populateTable(){
		directivesKey.add("ACHR");
		directivesMemImpact.add(true);
		directivesLabelAllowed.add(Assembler.LabelAllowed.OPTIONAL);
		directivesOperandType.add(8);
		
		directivesKey.add("ADRC");
		directivesMemImpact.add(true);
		directivesLabelAllowed.add(Assembler.LabelAllowed.OPTIONAL);
		directivesOperandType.add(10);
		
		directivesKey.add("ALT");
		directivesMemImpact.add(false);
		directivesLabelAllowed.add(Assembler.LabelAllowed.NOT_ALLOWED);
		directivesOperandType.add(16);
		
		directivesKey.add("AVERT");
		directivesMemImpact.add(false);
		directivesLabelAllowed.add(Assembler.LabelAllowed.NOT_ALLOWED);
		directivesOperandType.add(18);
		
		directivesKey.add("BEGIN");
		directivesMemImpact.add(false);
		directivesLabelAllowed.add(Assembler.LabelAllowed.REQUIRED);
		directivesOperandType.add(6);
		
		directivesKey.add("BSS");
		directivesMemImpact.add(true);
		directivesLabelAllowed.add(Assembler.LabelAllowed.OPTIONAL);
		directivesOperandType.add(11);
		
		directivesKey.add("DEBUG");
		directivesMemImpact.add(false);
		directivesLabelAllowed.add(Assembler.LabelAllowed.NOT_ALLOWED);
		directivesOperandType.add(15);
		
		directivesKey.add("DEC");
		directivesMemImpact.add(true);
		directivesLabelAllowed.add(Assembler.LabelAllowed.OPTIONAL);
		directivesOperandType.add(12);
		
		directivesKey.add("EQU");
		directivesMemImpact.add(false);
		directivesLabelAllowed.add(Assembler.LabelAllowed.REQUIRED);
		directivesOperandType.add(6);
		
		directivesKey.add("EXTRN");
		directivesMemImpact.add(false);
		directivesLabelAllowed.add(Assembler.LabelAllowed.NOT_ALLOWED);
		directivesOperandType.add(7);
		
		directivesKey.add("FINSH");
		directivesMemImpact.add(false);
		directivesLabelAllowed.add(Assembler.LabelAllowed.NOT_ALLOWED);
		directivesOperandType.add(0);
		
		directivesKey.add("HEX");
		directivesMemImpact.add(true);
		directivesLabelAllowed.add(Assembler.LabelAllowed.OPTIONAL);
		directivesOperandType.add(13);
		
		directivesKey.add("OCT");
		directivesMemImpact.add(true);
		directivesLabelAllowed.add(Assembler.LabelAllowed.OPTIONAL);
		directivesOperandType.add(14);
		
		directivesKey.add("PRMID");
		directivesMemImpact.add(false);		// This is what it says in the latest version of the spec, but may be wrong
		directivesLabelAllowed.add(Assembler.LabelAllowed.NOT_ALLOWED);
		directivesOperandType.add(9);
		
		directivesKey.add("PRMLST");
		directivesMemImpact.add(true);		// See above
		directivesLabelAllowed.add(Assembler.LabelAllowed.NOT_ALLOWED);
		directivesOperandType.add(17);
	}
}
